﻿/* 
   Copyright 2011 LUCA Studios LLC & John Evans

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

namespace LUCAStudios.Silverlight.Controls
{
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Markup;
    using System.Collections.Specialized;
    using System.Linq;

    /// <summary>
    /// A control for displaying a list of tool icons (or whatever) to the user.
    /// This control is a special kind of WindowBase control, and participates
    /// in docking/undocking.
    /// </summary>
    [TemplateVisualState(Name = "Normal", GroupName = "WindowDisplayMode")]
    [TemplateVisualState(Name = "NoUI", GroupName = "WindowDisplayMode")]
    [TemplateVisualState(Name = "Docked", GroupName = "WindowDisplayMode")]
    [ContentProperty("Children")]
    public class LUCAToolBar : WindowBase, IOrientingControl
    {
        private const double DefaultToolbarItemSize = 55;
        private bool _firstLoadOccurred;

        /// <summary>
        /// Constructor
        /// </summary>
        public LUCAToolBar()
        {
            DefaultStyleKey = typeof(LUCAToolBar);
        }
        
        private void UpdateToolbarDimensions()
        {
            if (VisualState != WindowLayoutState.Floating) return;

            //update the toolbar dimensions to reflect the changes
            var seps = Children.Where(o => o is LUCAToolBarSeparator);
            var items = Children.Where(o => o is LUCAToolBarItem);
            var longLength = (seps.Count() * 10) + (items.Count() * ToolbarItemSize) + 10;

            //update the toolbar window itself
            Width = Orientation == Orientation.Vertical ? ToolbarItemSize + 5 : longLength;
            Height = Orientation == Orientation.Vertical ? longLength : ToolbarItemSize + 5;
        }

        private void UpdateToolbarOrientation()
        {
            var seps = Children.Where(o => o is LUCAToolBarSeparator);
            var items = Children.Where(o => o is LUCAToolBarItem);

            //update the items and separators in the toolbar
            if (Orientation == Orientation.Horizontal)
            {
                foreach (var s in seps)
                {
                    s.Width = 1;
                    s.Height = ToolbarItemSize;
                    s.Margin = new Thickness(3, 3, 3, 3);
                }
            }
            else
            {
                foreach (var s in seps)
                {
                    s.Width = ToolbarItemSize;
                    s.Height = 1;
                    s.Margin = new Thickness(3, 3, 3, 3);
                }
            }

            foreach (var i in items)
            {
                i.Width = i.Height = ToolbarItemSize;
            } 
        }

        private static void OnOrientationChanging(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var o = d as LUCAToolBar;
            if (o == default(LUCAToolBar)) return;


            o.UpdateToolbarOrientation();
            o.UpdateToolbarDimensions();
        }

        #region overrides

        /// <summary>
        /// Called when the LUCA control is loaded
        /// </summary>
        protected override void OnLoaded()
        {
            base.OnLoaded();
            //if (_toolbarStackPanel == null)
            //    _toolbarStackPanel = this.FindElement<StackPanel>("spToolbarItems");
            UpdateToolbarOrientation();
            UpdateToolbarDimensions();
            if (!_firstLoadOccurred) _firstLoadOccurred = true;
        }

        /// <summary>
        /// Called by VisualState dependency property when VisualState is changing.  Should generally not be called directly.
        /// </summary>
        /// <param name="newState">The state to set the control's Visual State to.</param>
        protected override void SetVisualState(WindowLayoutState newState)
        {
            //force any visual state change of NoUI into floating state
            if (newState == WindowLayoutState.NoUI)
            {
                VisualState = WindowLayoutState.Floating;
            }
            else
            {
                base.SetVisualState(newState);
            }
        }

        /// <summary>
        /// Called when the Children collection changes
        /// </summary>
        /// <param name="e"></param>
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);
            UpdateToolbarDimensions();
            UpdateToolbarOrientation();
        }

        /// <summary>
        /// Performs a framework-safe add of a child to the collection
        /// Preferable over direct Add to the Children collection itself,
        /// because this method can be overriden by derived controls
        /// </summary>
        /// <param name="childToAdd"></param>
        public override void AddChild(ControlBase childToAdd)
        {
            base.AddChild(childToAdd);
            UpdateToolbarDimensions();
            UpdateToolbarOrientation();
        }

        /// <summary>
        /// When overridden in a derived class, is invoked whenever application code or internal processes (such as a rebuilding layout pass) call <see cref="M:System.Windows.Controls.Control.ApplyTemplate"/>. In simplest terms, this means the method is called just before a UI element displays in an application. For more information, see Remarks.
        /// </summary>
        public override void OnApplyTemplate()
        {
            if (_firstLoadOccurred)
            {
                var a = Children.Select(o => o).ToList();
                Children.Clear();
                LayoutContext.WindowManipulator.UnregisterWindow(this);
                UnRegisterDockEvents();

                base.OnApplyTemplate();

                foreach (var c in a)
                {
                    AddChild(c);
                }

                DragHandle = null;
                InitializeControlReferences();
                LayoutContext.WindowManipulator.RegisterWindow(this);
                RegisterDockEvents();
            }
            else
            {
                base.OnApplyTemplate();
            }
        }
        #endregion

        #region Dependency Properties

        /// <summary>
        /// A backing property for the Orientation Dependency Property
        /// </summary>
        public static readonly DependencyProperty OrientationProperty =
    DependencyProperty.Register("Orientation", typeof(Orientation), typeof(LUCAToolBar), new PropertyMetadata(Orientation.Vertical, OnOrientationChanging));

        /// <summary>
        /// Specifies the Orientation of the given IOrientingControl
        /// </summary>
        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        /// <summary>
        /// A backing property for the ToolbarItemSize Dependency Property
        /// </summary>
        public static readonly DependencyProperty ToolbarItemSizeProperty =
            DependencyProperty.Register("ToolbarItemSize", typeof(double), typeof(LUCAToolBar), new PropertyMetadata(DefaultToolbarItemSize));

        /// <summary>
        /// A dependency property that specifies the height/width of LUCAToolBarItem controls
        /// </summary>
        public double ToolbarItemSize
        {
            get { return (double)GetValue(ToolbarItemSizeProperty); }
            set { SetValue(ToolbarItemSizeProperty, value); }
        }

        #endregion
    }
}
